﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Centny.PdfReader.IO
{
    public class ByteReader
    {
        //private Stream _BaseStream;
        private Stream BaseStream
        {
            get;
            set;
        }
        public long Position
        {
            get
            {
                return this.BaseStream.Position - 2;
            }
            set
            {
                this.BaseStream.Position = value;
                this.PrapreCurrent();
                //this.BaseStream.Position = value;
            }
        }
        private void PrapreCurrent()
        {
            byte[] bys = new byte[2];
            this.BaseStream.Read(bys, 0, 2);
            this._Current = bys[0];
            this._Next = bys[1];
        }
        public long Length
        {
            get
            {
                return this.BaseStream.Length;
            }
        }
        public bool Eof
        {
            get
            {
                return this.Position >= this.Length || this.Current == -1;
            }
        }
        private int _Current;
        public int Current
        {
            get
            {
                return this._Current;
            }
        }
        public char CurrentChar
        {
            get
            {
                return (char)this._Current;
            }
        }
        private int _Next;
        public int Next
        {
            get
            {
                return this._Next;
            }
        }
        public char NextChar
        {
            get
            {
                return (char)this._Next;
            }
        }
        public ByteReader(Stream bs)
        {
            this.BaseStream = bs;
            this.Position = 0;
        }
        public virtual int Read()
        {
            if (this.Current == -1)
            {
                return this.Current;
            }
            int v = this.BaseStream.ReadByte();
            int c = this.Current;
            this._Current = this.Next;
            this._Next = v;
            return c;
        }
        public virtual char ReadChar()
        {
            return (char)this.Read();
        }
        public virtual byte ReadByte()
        {
            return (byte)this.Read();
        }
        public virtual int Peek()
        {
            return this.Current;
        }
        public virtual char PeekChar()
        {
            return (char)this.Peek();
        }
        public virtual byte PeekByte()
        {
            return (byte)this.Peek();
        }
        public virtual bool ToBlock(char[] b)
        {
            while (!this.Eof)
            {
                for (int i = 0; i < b.Length && !this.Eof; i++)
                {
                    if (this.ReadChar() != b[i])
                    {
                        break;
                    }
                    if (i == b.Length - 1)
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        public virtual bool ToBlock(String b)
        {
            return this.ToBlock(b.ToCharArray());
        }
        public virtual String ReadLine()
        {
            StringBuilder sb = new StringBuilder();
            while (!this.Eof)
            {
                char c = this.ReadChar();
                if (c == '\n')
                {
                    break;
                }
                sb.Append(c);
            }
            return sb.ToString();
        }
        public virtual int Read(byte[] buf, int offset, int count)
        {
            if (this.Current == -1)
            {
                return -1;
            }
            buf[offset + 0] = (byte)this.Current;
            if (this.Next == -1)
            {
                return 1;
            }
            buf[offset + 1] = (byte)this.Next;
            int size = this.BaseStream.Read(buf, offset + 2, count - 2);
            this.PrapreCurrent();
            return size + 2;
        }
        private class State
        {
            public long Position;
            public int Current;
            public int Next;
        }
        private Stack<State> States = new Stack<State>();
        public virtual void PushState()
        {
            State s = new State();
            s.Position = this.Position;
            s.Current = this.Current;
            s.Next = this.Next;
            this.States.Push(s);
        }
        public virtual void PopState()
        {
            State s = this.States.Pop();
            this.Position = s.Position;
            this._Current = s.Current;
            this._Next = s.Next;
        }
    }
}
